package com.sky.service.user.Impl;


import com.alibaba.fastjson.JSON;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.sky.WebSocket.WebSocketServer;
import com.sky.WebSocket.WebSocketTask;
import com.sky.context.BaseContext;
import com.sky.dto.OrdersConfirmDTO;
import com.sky.dto.OrdersSubmitDTO;
import com.sky.exception.BaseException;
import com.sky.mapper.admin.CategoryMapper;
import com.sky.mapper.user.AddressBookMapper;
import com.sky.mapper.user.ShoppingCartMapper;
import com.sky.mapper.user.UserOrderMapper;
import com.sky.pojo.*;
import com.sky.result.PageResult;
import com.sky.service.user.UserOrderService;
import com.sky.vo.OrderSubmitVO;
import com.sky.vo.OrderVO;
import lombok.extern.slf4j.Slf4j;

import org.apache.ibatis.annotations.Select;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;


import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
public class UserOrderServiceImpl implements UserOrderService {


    @Autowired//注入websocket通知
    private WebSocketServer webSocketServer;
    @Autowired
    private WebSocketTask webSocketTask;

    @Autowired
    private CategoryMapper categoryMapper;
    @Autowired
    public UserOrderMapper orderMapper;
    @Autowired
    public AddressBookMapper addressBookMapper;
    @Autowired
    private ShoppingCartMapper shoppingCartMapper;


    /**
     * 模拟用户支付成功
     * 根据用户的订单号查询 并模拟成功
     *
     * @param num
     */
    @Override
    public String paySuccess(String num) {
        //更新订单状态（1.获取订单信息）
        Orders orders = orderMapper.getByNumer(num);
        //判断为null 则订单bu存在
        if (orders == null) {
            log.info("订单不存在");
        } else {  //存在，设置新的信息
            orders.setPayStatus(Orders.PAID);//设置支付状1 已支付
            orders.setStatus(Orders.TO_BE_CONFIRMED);//设置付款成功2
            //去数据库修改订单信息
            orderMapper.upPayStatusOk(orders);
        }
        //发送websocket 通知  设置前端需要返回的参数
        Map<String, Object> map = new HashMap<>();
        //设置前端需要返回的参数
        map.put("type", 1);//1催单
        map.put("orderId", orders.getId());
        map.put("content", "您有新的订单了，请及时处理");//这个一般是产品经理规定写什么
        //前端需要的是json格式
        String jsonString = JSON.toJSONString(map);
        //调用这个类中的   来电提醒的方法   传入需要播报的 json串
        webSocketServer.SendOrderComeReminder(jsonString);
        return jsonString;

    }

    /**
     * 用户催单
     *
     * @param orderId
     */
    @Override
    public String cuiDan(Long orderId) {
        //根据用户传入的id查询获取订单
        Orders orders = orderMapper.getByOrderId(orderId);
        if (orders == null) {
            log.info("订单不存在,不能催单");
        } else if (orders.getPayStatus() != 1) //已付款状态
            orders.setPayStatus(Orders.TO_BE_CONFIRMED);//设置为催单状态
        //更改状态
        orderMapper.upPayStatus2(orders);
        log.info("开始催单处理");
        //用户催单
        Map<String, Object> map = new HashMap<>();
        map.put("type", 2);//约定服务2为催单
        map.put("ordeid", orderId);
        map.put("content", "用户已经开始催单了，请尽快完成");


        //转josn传格式返回
        String jsonString = JSON.toJSONString(map);

        //同时可以调用类写的 语音提醒 方法  进行语音播报催单内容    语音播
        webSocketServer.SendOrderComeReminder(jsonString);
        log.info("催单已成功，催单内容为：{}", jsonString);

        return jsonString;

    }


    /**
     * 支付
     *
     * @param dto
     * @return
     */
    @Override
    @Transactional  //事务
    public OrderSubmitVO sumit(OrdersSubmitDTO dto) {
        //本质就是封装两张表的数据（1.订单表Orders  2.订单明细表OrderDetail）
        //所有逻辑：封装表中的数据

        //订单表，1.请求参数拷贝进订单 2.补齐空缺的参数
        Orders orders = new Orders();
        BeanUtils.copyProperties(dto, orders);
        orders.setAmount(dto.getAmount());//实收金额(菜品信息相加）需要改，暂写前端传如的（注意：一定不能前端传入）
        orders.setOrderTime(LocalDateTime.now());//当前时间为下单时间
        orders.setPayStatus(Orders.UN_PAID);//支付方式，设置为默认（方法中设置了变量）
        orders.setStatus(Orders.PENDING_PAYMENT);//订单状态 设置为默认待付款


        orders.setNumber(UUID.randomUUID().toString());//下单人号码 这里不能这么写
        orders.setUserId(BaseContext.getCurrentId());//下单人id 就是操作人id

        //从购物车获取用户人信息(从请求输入中获取用户人的id)
        AddressBook addressBook = addressBookMapper.getById(dto.getAddressBookId());

        if (addressBook == null) {
            throw new BaseException("地址错误");
        }

        orders.setUserName(addressBook.getConsignee());//下单人名字
        orders.setPhone(addressBook.getPhone());//下单人手机号
        //获取地址（在用户人的资料里，由 ：省+市+区+详细地址拼接）
        orders.setAddress(addressBook.getProvinceName() + addressBook.getCityName() + addressBook.getDistrictName() + addressBook.getDetail());
        //计算出餐时间=当前时间+菜品制作时间
        Integer makeTime = shoppingCartMapper.getMakeTime(BaseContext.getCurrentId());
        orders.setMealTime(LocalDateTime.now().minusMinutes(makeTime));//调用工具类计算+的时间
        orderMapper.insert(orders);//在.订单表Orders 插入数据 已有的数据进行保存

        //插入OrderDetail订单详情表(查看购物车的所有产品)
        List<ShoppingCart> shoppingCarts = shoppingCartMapper.getShopping(BaseContext.getCurrentId());
        if (CollectionUtils.isEmpty(shoppingCarts)) {
            throw new BaseException("购物车没有数据");
        }
        //创建订单集合
        List<OrderDetail> orderDetailList = new ArrayList<>();
        //遍历购物车
        for (ShoppingCart shoppingCart : shoppingCarts) {
            OrderDetail detail = new OrderDetail();
            BeanUtils.copyProperties(shoppingCart, detail); //把购物车现有的东西 拷贝进订单集合 准备后续支付
        }

        orderMapper.insertBatch(orderDetailList);//把订单集合添加进数据库
        //清空购物车数据
        shoppingCartMapper.deleteByUserId(BaseContext.getCurrentId());//根据操作人

        //封装返回结果
        OrderSubmitVO orderSubmit = new OrderSubmitVO();//需要返回的结果
        orderSubmit.setId(orders.getId());
        orderSubmit.setOrderAmount(orders.getAmount());
        orderSubmit.setOrderTime(orders.getOrderTime());
        return orderSubmit;
    }


    /**
     * 查询历史订单
     *
     * @param
     * @return
     */
    @Override
    public PageResult getPage(Integer page, Integer pageSize) {
        OrdersConfirmDTO dto = new OrdersConfirmDTO();
        dto.setPage(page);
        dto.setPageSize(pageSize);
        dto.setStatus(5);//已完成

        log.info("设置分页{}", page);
        log.info("设置分页长{}", pageSize);
        log.info("状态{}", dto.getStatus());

        //分页工具类 获取分页 动态sql
        PageHelper.startPage(dto.getPage(), dto.getPageSize());
        //去查询后封装为Page<OrderDetail>工具类的 此返回集合
        // page这个集合就可以把总记录和当前页集合get出来 装进去对象里
        Page<Orders> Page = categoryMapper.getPage(dto);
        log.info("查询后的数据为{},{}", Page);
        //new成对象 把集合中封装的 结果取出来 塞进需要返回的对象里
        PageResult pageResult = new PageResult(Page.getTotal(), Page.getResult());

        return pageResult;
    }

    /**
     * 根据状态查询订单
     *
     * @param status
     * @return
     */
    @Override
    public PageResult getByStatus(Integer status) {
        OrdersConfirmDTO dto = new OrdersConfirmDTO();
        dto.setPage(1);
        dto.setPageSize(10);
        dto.setStatus(status);
        PageHelper.startPage(dto.getPage(), dto.getPageSize());
        //PageResult类红封装着总记录数和当页集合
        Page<PageResult> page = categoryMapper.getByStatus(dto.getStatus());
        //创建返回对象，把数据取出来装进去
        PageResult  pageResult = new PageResult(page.getTotal(), page.getResult());
        return pageResult;
    }

    /**
     * 根据id取消订单
     *
     * @param id
     */
    @Override
    public void quXiao(Integer id) {
        //根据id 获取订单信息
        Orders orders = categoryMapper.getOrders(id);
        //判断：为null 订单不存在
        if (orders == null) {
            log.info("订单不存在");
        }
        //不为null
        else {
            //1.待支付和待接单状态下，用户可以直接取消订单
            //1.1）status=1， pay_status=0,
            Integer payStatus = orders.getPayStatus();
            Integer status = orders.getStatus();
            if (payStatus == 0 & status == 1) {
                //1.2）设置订单信息status=8(退款中，取消中)
                //1.3)调用退款方法（执行退款）
                log.info("调用退款，执行退款");
                //1.4）完成退款
                log.info("完成退款，数据库更改状态");
            }
            //2.商家已接单状态下，用户取消订单需要电话沟通商家
            //2.1）status=3，
            else if (status == 3) {
                //2.2）向前端发送信息 注入WebSocketTask 向前端发送信息
                webSocketTask.iponeGouTong("商家已接单，取消订单请电话沟通商家");
                log.info("商家已接单，取消订单需电联");
            }
            //3.派送状态下，用户取消订单需要电话沟通商家
            else if (status == 4 | status == 5)
            //3.1）status=4 or 5， 向前端发送信息
            {
                log.info("派送状态中，取消订单需电联");
                webSocketTask.iponeGouTong("派送状态中，取消订单请电话沟通商家");
            }
            //4.如果在待接单状态下取消订单，需要给用户退款
            //4.1）status=2
            else if (status == 2)
            //4.2）设置订单信息status=8(退款中，取消中)
            //4.3)调用退款方法（执行退款）
            {
                log.info("调用退款，执行退款");
                //4.4）完成退款
                log.info("完成退款，数据库更改状态");
            }


            //5.取消订单后需要将订单状态修改为”已取消“
            //5.1)最后更新数据库信息(status=7，pay_status=2,）
            orders.setPayStatus(2);
            orders.setStatus(7);
            categoryMapper.updateOrders(orders);
        }
    }

    /**
     * 根据订单id 再来一单
     *
     * @param id
     */
    @Override
    public void oneRepetition(Integer id) {
        log.info("订单id{}",id);
        //根据订单id 获得订单信息
        Orders orders = categoryMapper.getOrders(id);
        if (orders == null) {
            log.info("订单不存在");
        }
        //修改订单信息
        orders.setStatus(Orders.UN_PAID);
        orders.setPayStatus(Orders.UN_PAID);
        orders.setOrderTime(LocalDateTime.now());

        //新增订单
        categoryMapper.oneRepetition(orders);
    }


    /**
     * 根据订单id查询顾客订单信息
     *
     * @param orderId
     * @return
     */
    @Override
    public OrderVO getOrderDetali(Integer orderId) {
        log.info("请求参数orderId是#{}", orderId);
        //获取订单
        Orders orders = orderMapper.getOrderDetali(orderId);
        if (orders == null) {
            log.info("顾客订单不存在");
        }
        List<OrderDetail> orderDetaliList = orderMapper.getOrderDetaliList(orderId);
        if (orderDetaliList == null) {
            log.info("菜品集合不存在");
        }
        //封装数据
        OrderVO orderVO = new OrderVO();
        log.info("封装之前的数据{}", orderVO);

        orderVO.setWaybillStatus(orders.getStatus());//对应订单状态
        orderVO.setOrderDetailList(orderDetaliList);//订单详情
        //菜品集合
        String orderDetailString = orderDetaliList.stream()
                .map(orderDetail -> orderDetail.toString())//使用lambda表达式 四阿姨to String
                .collect(Collectors.joining(","));//使用逗号分割每个orderDetail的字符串
        //转字符串格式
        orderVO.setOrderDishes(orderDetailString);//订单菜品信息 字符串
        log.info("转字符串格式{}", orderDetailString);


        //根据订单编号（运单号）  获取骑手信息
        log.info("订单NUM号码是{}", orders.getNumber());
        Courier courier = orderMapper.getCourider(orders.getNumber());
        if (courier != null) {
            log.info("骑手电话{}", courier.getTelephone());
            orderVO.setCourierTelephone(courier.getTelephone());//骑手电话
        }

        log.info("商铺id是{}", orders.getShopId());
        //根据商铺Id 获取商铺信息
        Merchant merchant = orderMapper.getMerchant(orders.getShopId());
        if (merchant != null) {
            orderVO.setShopName(merchant.getShopName());//商铺名称
            orderVO.setShopTelephone(merchant.getShopTelephone());//商铺电话
        } else {
            log.info("商铺信息不存在{}", merchant);
        }

        //根据下单id  获取获取下单用户的信息
        AddressBook addressBook = addressBookMapper.getById(orders.getUserId());
        if (addressBook != null) {
            orderVO.setSex(addressBook.getSex());//顾客性别
        } else {
            log.info("顾客信息不存在{}", addressBook);
        }
        log.info("封装后的数据{}", orderVO);
        return orderVO;
    }


    //↓    以下是：C端


    /**
     * 小程序，无条件查询分类
     *
     * @return
     */
    @Override
    @Select("select * from category")
    public List<Category> getCategory() {
        log.info("无条件查询分类");
        List<Category> categoryList = categoryMapper.getCategory();
        return categoryList;
    }

}
